import serial
import serial.tools.list_ports
import logging
from queue import Queue
from utils.threading_utils import StoppableThread
import time

class SerialManager:
    """串口管理类"""

    def __init__(self, config):
        self.config = config
        self.serial_port = None
        self.rx_queue = Queue()
        self.tx_queue = Queue()
        self.connected = False
        self.serial_thread = None

    def get_available_ports(self):
        """获取可用串口列表"""
        ports = [port.device for port in serial.tools.list_ports.comports()]
        return ports

    def connect(self, port=None):
        """连接串口设备"""
        if self.connected:
            return True

        # 获取配置
        serial_config = self.config.get_serial_config()

        try:
            # 创建串口连接
            self.serial_port = serial.Serial(
                port=port or serial_config.get("port", ""),
                baudrate=serial_config.get("baudrate", 9600),
                bytesize=serial_config.get("bytesize", serial.EIGHTBITS),
                parity=self._parse_parity(serial_config.get("parity", "none")),
                stopbits=self._parse_stopbits(serial_config.get("stopbits", 1)),
                timeout=serial_config.get("timeout", 0.1)
            )

            if self.serial_port.is_open:
                self.connected = True
                self._start_serial_thread()
                logging.info(f"串口连接成功: {self.serial_port.port}")
                return True
            return False
        except serial.SerialException as e:
            logging.error(f"串口连接失败: {str(e)}")
            return False

    def disconnect(self):
        """断开串口连接"""
        if self.connected:
            self.connected = False

            # 停止串口线程
            if self.serial_thread and self.serial_thread.is_alive():
                self.serial_thread.stop()
                self.serial_thread.join(timeout=1.0)

            # 关闭串口
            if self.serial_port and self.serial_port.is_open:
                self.serial_port.close()

            logging.info("串口已断开")

    def send_data(self, data):
        """发送数据到串口"""
        if self.connected and self.serial_port.is_open:
            self.tx_queue.put(data)

    def receive_data(self):
        """从串口接收数据"""
        if not self.rx_queue.empty():
            return self.rx_queue.get()
        return None

    def _start_serial_thread(self):
        """启动串口读写线程"""
        self.serial_thread = SerialThread(self)
        self.serial_thread.start()

    def _parse_parity(self, parity_str):
        """解析校验位字符串"""
        parity_map = {
            "none": serial.PARITY_NONE,
            "even": serial.PARITY_EVEN,
            "odd": serial.PARITY_ODD,
            "mark": serial.PARITY_MARK,
            "space": serial.PARITY_SPACE
        }
        return parity_map.get(parity_str.lower(), serial.PARITY_NONE)

    def _parse_stopbits(self, stopbits):
        """解析停止位"""
        if isinstance(stopbits, str):
            stopbits = float(stopbits)

        if stopbits == 1:
            return serial.STOPBITS_ONE
        elif stopbits == 1.5:
            return serial.STOPBITS_ONE_POINT_FIVE
        elif stopbits == 2:
            return serial.STOPBITS_TWO
        else:
            return serial.STOPBITS_ONE


class SerialThread(StoppableThread):
    """串口读写线程"""

    def __init__(self, serial_manager):
        super().__init__()
        self.serial_manager = serial_manager
        self.serial_port = serial_manager.serial_port

    def run(self):
        """线程主循环"""
        logging.info("串口线程启动")

        while not self.stopped() and self.serial_manager.connected:
            try:
                # 处理发送队列
                self._process_tx_queue()

                # 处理接收数据
                self._process_rx_data()

                # 短暂休眠，避免CPU占用过高
                time.sleep(0.01)

            except serial.SerialException as e:
                logging.error(f"串口通信错误: {str(e)}")
                self.serial_manager.disconnect()
                break
            except Exception as e:
                logging.error(f"串口线程错误: {str(e)}")
                time.sleep(0.1)

        logging.info("串口线程停止")

    def _process_tx_queue(self):
        """处理发送队列"""
        while not self.serial_manager.tx_queue.empty():
            data = self.serial_manager.tx_queue.get()
            try:
                self.serial_port.write(data)
                logging.debug(f"发送数据: {data.hex(' ').upper()}")
            except Exception as e:
                logging.error(f"发送数据失败: {str(e)}")

    def _process_rx_data(self):
        """处理接收数据"""
        if self.serial_port.in_waiting > 0:
            try:
                data = self.serial_port.read(self.serial_port.in_waiting)
                if data:
                    self.serial_manager.rx_queue.put(data)
                    logging.debug(f"接收数据: {data.hex(' ').upper()}")
            except Exception as e:
                logging.error(f"接收数据失败: {str(e)}")